<!--
 * @Description: cron表达式生成插件
 * @Author: DHL
 * @Date: 2022-04-13 14:09:03
 * @LastEditors: DHL
 * @LastEditTime: 2022-12-11 20:13:17
-->

<template>
  <div class="tw-cron-wrapper">
    <div class="left-wrapper">
      <el-tabs v-model="tabsActiveName">
        <el-tab-pane label="秒" name="second">
          <div class="config-list second">
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="second.type"
                :label="TYPE_EVERY"
                :disabled="second.disabled"
              >
                每秒
              </el-radio>
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="second.type"
                :label="TYPE_RANGE"
                :disabled="second.disabled"
              >
                区间
              </el-radio>
              从
              <el-input-number
                :size="cronSize"
                v-model="second.range.start"
                :min="second.minValue"
                :max="second.maxValue"
                controls-position="right"
                :disabled="second.disabled || second.type != TYPE_RANGE"
              />
              秒 至
              <el-input-number
                :size="cronSize"
                v-model="second.range.end"
                :min="second.minValue"
                :max="second.maxValue"
                controls-position="right"
                :disabled="second.disabled || second.type != TYPE_RANGE"
              />
              秒
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="second.type"
                :label="TYPE_LOOP"
                :disabled="second.disabled"
              >
                循环
              </el-radio>
              从
              <el-input-number
                :size="cronSize"
                v-model="second.loop.start"
                :min="second.minValue"
                :max="second.maxValue"
                controls-position="right"
                :disabled="second.disabled || second.type != TYPE_LOOP"
              />
              秒开始， 间隔
              <el-input-number
                :size="cronSize"
                v-model="second.loop.interval"
                :min="second.minValue"
                :max="second.maxValue"
                controls-position="right"
                :disabled="second.disabled || second.type != TYPE_LOOP"
              />
              秒
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="second.type"
                :label="TYPE_SPECIFY"
                :disabled="second.disabled"
              >
                指定
              </el-radio>
              <div class="list">
                <el-checkbox-group v-model="second.valueList">
                  <el-checkbox
                    v-for="item in second.maxValue + 1"
                    :key="`second-${item}`"
                    :label="`${item - 1}`"
                    :size="cronSize"
                    :disabled="second.disabled || second.type != TYPE_SPECIFY"
                  />
                </el-checkbox-group>
              </div>
            </div>
          </div>
        </el-tab-pane>

        <el-tab-pane label="分" name="minute">
          <div class="config-list minute">
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="minute.type"
                :label="TYPE_EVERY"
                :disabled="minute.disabled"
              >
                每分
              </el-radio>
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="minute.type"
                :label="TYPE_RANGE"
                :disabled="minute.disabled"
              >
                区间
              </el-radio>
              从
              <el-input-number
                :size="cronSize"
                v-model="minute.range.start"
                :min="minute.minValue"
                :max="minute.maxValue"
                controls-position="right"
                :disabled="minute.disabled || minute.type != TYPE_RANGE"
              />
              分 至
              <el-input-number
                :size="cronSize"
                v-model="minute.range.end"
                :min="minute.minValue"
                :max="minute.maxValue"
                controls-position="right"
                :disabled="minute.disabled || minute.type != TYPE_RANGE"
              />
              分
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="minute.type"
                :label="TYPE_LOOP"
                :disabled="minute.disabled"
              >
                循环
              </el-radio>
              从
              <el-input-number
                :size="cronSize"
                v-model="minute.loop.start"
                :min="minute.minValue"
                :max="minute.maxValue"
                controls-position="right"
                :disabled="minute.disabled || minute.type != TYPE_LOOP"
              />
              分开始， 间隔
              <el-input-number
                :size="cronSize"
                v-model="minute.loop.interval"
                :min="minute.minValue"
                :max="minute.maxValue"
                controls-position="right"
                :disabled="minute.disabled || minute.type != TYPE_LOOP"
              />
              分
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="minute.type"
                :label="TYPE_SPECIFY"
                :disabled="minute.disabled"
              >
                指定
              </el-radio>
              <div class="list">
                <el-checkbox-group v-model="minute.valueList">
                  <el-checkbox
                    v-for="item in minute.maxValue + 1"
                    :key="`minute-${item}`"
                    :label="`${item - 1}`"
                    :size="cronSize"
                    :disabled="minute.disabled || minute.type != TYPE_SPECIFY"
                  />
                </el-checkbox-group>
              </div>
            </div>
          </div>
        </el-tab-pane>

        <el-tab-pane label="时" name="hour">
          <div class="config-list hour">
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="hour.type"
                :label="TYPE_EVERY"
                :disabled="hour.disabled"
              >
                每时
              </el-radio>
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="hour.type"
                :label="TYPE_RANGE"
                :disabled="hour.disabled"
              >
                区间
              </el-radio>
              从
              <el-input-number
                :size="cronSize"
                v-model="hour.range.start"
                :min="hour.minValue"
                :max="hour.maxValue"
                controls-position="right"
                :disabled="hour.disabled || hour.type != TYPE_RANGE"
              />
              时 至
              <el-input-number
                :size="cronSize"
                v-model="hour.range.end"
                :min="hour.minValue"
                :max="hour.maxValue"
                controls-position="right"
                :disabled="hour.disabled || hour.type != TYPE_RANGE"
              />
              时
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="hour.type"
                :label="TYPE_LOOP"
                :disabled="hour.disabled"
              >
                循环
              </el-radio>
              从
              <el-input-number
                :size="cronSize"
                v-model="hour.loop.start"
                :min="hour.minValue"
                :max="hour.maxValue"
                controls-position="right"
                :disabled="hour.disabled || hour.type != TYPE_LOOP"
              />
              时开始， 间隔
              <el-input-number
                :size="cronSize"
                v-model="hour.loop.interval"
                :min="hour.minValue"
                :max="hour.maxValue"
                controls-position="right"
                :disabled="hour.disabled || hour.type != TYPE_LOOP"
              />
              时
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="hour.type"
                :label="TYPE_SPECIFY"
                :disabled="hour.disabled"
              >
                指定
              </el-radio>
              <div class="list">
                <el-checkbox-group v-model="hour.valueList">
                  <el-checkbox
                    v-for="item in hour.maxValue + 1"
                    :key="`hour-${item}`"
                    :label="`${item - 1}`"
                    :size="cronSize"
                    :disabled="hour.disabled || hour.type != TYPE_SPECIFY"
                  />
                </el-checkbox-group>
              </div>
            </div>
          </div>
        </el-tab-pane>

        <el-tab-pane label="日" name="day">
          <div class="config-list day">
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="day.type"
                :label="TYPE_NOT_SET"
                :disabled="dayDisable"
              >
                不设置
              </el-radio>
              <span class="info">日和周只能设置其中之一</span>
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="day.type"
                :label="TYPE_EVERY"
                :disabled="dayDisable"
              >
                每日
              </el-radio>
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="day.type"
                :label="TYPE_RANGE"
                :disabled="dayDisable"
              >
                区间
              </el-radio>
              从
              <el-input-number
                :size="cronSize"
                v-model="day.range.start"
                :min="day.minValue"
                :max="day.maxValue"
                controls-position="right"
                :disabled="dayDisable || day.type != TYPE_RANGE"
              />
              日 至
              <el-input-number
                :size="cronSize"
                v-model="day.range.end"
                :min="day.minValue"
                :max="day.maxValue"
                controls-position="right"
                :disabled="dayDisable || day.type != TYPE_RANGE"
              />
              日
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="day.type"
                :label="TYPE_LOOP"
                :disabled="dayDisable"
              >
                循环
              </el-radio>
              从
              <el-input-number
                :size="cronSize"
                v-model="day.loop.start"
                :min="day.minValue"
                :max="day.maxValue"
                controls-position="right"
                :disabled="dayDisable || day.type != TYPE_LOOP"
              />
              日开始， 间隔
              <el-input-number
                :size="cronSize"
                v-model="day.loop.interval"
                :min="day.minValue"
                :max="day.maxValue"
                controls-position="right"
                :disabled="dayDisable || day.type != TYPE_LOOP"
              />
              日
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="day.type"
                :label="TYPE_WORK"
                :disabled="dayDisable"
              >
                工作日
              </el-radio>
              本月
              <el-input-number
                :size="cronSize"
                v-model="day.valueWork"
                :min="day.minValue"
                :max="day.maxValue"
                controls-position="right"
                :disabled="dayDisable || day.type != TYPE_WORK"
              />
              日，最近的工作日
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="day.type"
                :label="TYPE_LAST"
                :disabled="dayDisable"
              >
                最后一日
              </el-radio>
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="day.type"
                :label="TYPE_SPECIFY"
                :disabled="dayDisable"
              >
                指定
              </el-radio>
              <div class="list">
                <el-checkbox-group v-model="day.valueList">
                  <el-checkbox
                    v-for="item in day.maxValue"
                    :key="`day-${item}`"
                    :label="`${item}`"
                    :size="cronSize"
                    :disabled="dayDisable || day.type != TYPE_SPECIFY"
                  />
                </el-checkbox-group>
              </div>
            </div>
          </div>
        </el-tab-pane>

        <el-tab-pane label="月" name="month">
          <div class="config-list month">
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="month.type"
                :label="TYPE_EVERY"
                :disabled="month.disabled"
              >
                每月
              </el-radio>
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="month.type"
                :label="TYPE_RANGE"
                :disabled="month.disabled"
              >
                区间
              </el-radio>
              从
              <el-input-number
                :size="cronSize"
                v-model="month.range.start"
                :min="month.minValue"
                :max="month.maxValue"
                controls-position="right"
                :disabled="month.disabled || month.type != TYPE_RANGE"
              />
              月 至
              <el-input-number
                :size="cronSize"
                v-model="month.range.end"
                :min="month.minValue"
                :max="month.maxValue"
                controls-position="right"
                :disabled="month.disabled || month.type != TYPE_RANGE"
              />
              月
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="month.type"
                :label="TYPE_LOOP"
                :disabled="month.disabled"
              >
                循环
              </el-radio>
              从
              <el-input-number
                :size="cronSize"
                v-model="month.loop.start"
                :min="month.minValue"
                :max="month.maxValue"
                controls-position="right"
                :disabled="month.disabled || month.type != TYPE_LOOP"
              />
              月开始， 间隔
              <el-input-number
                :size="cronSize"
                v-model="month.loop.interval"
                :min="month.minValue"
                :max="month.maxValue"
                controls-position="right"
                :disabled="month.disabled || month.type != TYPE_LOOP"
              />
              月
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="month.type"
                :label="TYPE_SPECIFY"
                :disabled="month.disabled"
              >
                指定
              </el-radio>
              <div class="list">
                <el-checkbox-group v-model="month.valueList">
                  <el-checkbox
                    v-for="item in month.maxValue"
                    :key="`month-${item}`"
                    :label="`${item}`"
                    :size="cronSize"
                    :disabled="month.disabled || month.type != TYPE_SPECIFY"
                  />
                </el-checkbox-group>
              </div>
            </div>
          </div>
        </el-tab-pane>

        <el-tab-pane label="周" name="week">
          <div class="config-list week">
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="week.type"
                :label="TYPE_NOT_SET"
                :disabled="weekDisable"
              >
                不设置
              </el-radio>
              <span class="info">日和周只能设置其中之一</span>
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="week.type"
                :label="TYPE_RANGE"
                :disabled="weekDisable"
              >
                区间
              </el-radio>
              从
              <el-select
                :size="cronSize"
                v-model="week.range.start"
                :disabled="weekDisable || week.type != TYPE_RANGE"
              >
                <el-option
                  v-for="(val, key) of week.weekMap"
                  :key="`week-range-left-${val}`"
                  :label="key"
                  :value="val"
                />
              </el-select>
              至
              <el-select
                :size="cronSize"
                v-model="week.range.end"
                :disabled="weekDisable || week.type != TYPE_RANGE"
              >
                <el-option
                  v-for="(val, key) of week.weekMap"
                  :key="`week-range-right-${val}`"
                  :label="key"
                  :value="val"
                />
              </el-select>
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="week.type"
                :label="TYPE_LOOP"
                :disabled="weekDisable"
              >
                循环
              </el-radio>
              从
              <el-select
                :size="cronSize"
                v-model="week.loop.start"
                :disabled="weekDisable || week.type != TYPE_LOOP"
              >
                <el-option
                  v-for="(val, key) of week.weekMap"
                  :key="`week-loop-left-${val}`"
                  :label="key"
                  :value="val"
                />
              </el-select>
              开始， 间隔
              <el-input-number
                :size="cronSize"
                v-model="week.loop.interval"
                :min="week.minValue"
                :max="week.maxValue"
                controls-position="right"
                :disabled="weekDisable || week.type != TYPE_LOOP"
              />
              天
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="week.type"
                :label="TYPE_SPECIFY"
                :disabled="weekDisable"
              >
                指定
              </el-radio>
              <div class="list">
                <el-checkbox-group v-model="week.valueList">
                  <el-checkbox
                    v-for="(val, key) of week.weekMap"
                    :key="`week-${val}`"
                    :label="`${val}`"
                    :size="cronSize"
                    :disabled="weekDisable || week.type != TYPE_SPECIFY"
                  >
                    {{ key }}
                  </el-checkbox>
                </el-checkbox-group>
              </div>
            </div>
          </div>
        </el-tab-pane>

        <el-tab-pane label="年" name="year">
          <div class="config-list year">
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="year.type"
                :label="TYPE_EVERY"
                :disabled="year.disabled"
              >
                每年
              </el-radio>
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="year.type"
                :label="TYPE_RANGE"
                :disabled="year.disabled"
              >
                区间
              </el-radio>
              从
              <el-input-number
                :size="cronSize"
                v-model="year.range.start"
                :min="nowYear"
                controls-position="right"
                :disabled="year.disabled || year.type != TYPE_RANGE"
              />
              年 至
              <el-input-number
                :size="cronSize"
                v-model="year.range.end"
                :min="year.range.start"
                controls-position="right"
                :disabled="year.disabled || year.type != TYPE_RANGE"
              />
              年
            </div>
            <div class="item">
              <el-radio
                :size="cronSize"
                v-model="year.type"
                :label="TYPE_LOOP"
                :disabled="year.disabled"
              >
                循环
              </el-radio>
              从
              <el-input-number
                :size="cronSize"
                v-model="year.loop.start"
                :min="nowYear"
                controls-position="right"
                :disabled="year.disabled || year.type != TYPE_LOOP"
              />
              年开始， 间隔
              <el-input-number
                :size="cronSize"
                v-model="year.loop.interval"
                :min="1"
                controls-position="right"
                :disabled="year.disabled || year.type != TYPE_LOOP"
              />
              年
            </div>
          </div>
        </el-tab-pane>
      </el-tabs>
    </div>

    <div>
      <el-divider direction="vertical" />
    </div>

    <div class="right-wrapper">
      <div class="table">
        <el-table :data="tableData" stripe :show-header="false">
          <el-table-column prop="name" label="名称" align="center" width="120" />
          <el-table-column prop="value" label="值" />
        </el-table>
      </div>
      <div class="exe-time">
        <div class="lable">执行时间：</div>
        <el-date-picker
          v-model="startTime"
          type="datetime"
          placeholder="请选择执行时间"
          @change="calTriggerList"
        />
      </div>
      <div class="exe-preview">
        <div class="lable">执行预览：<span>执行预览解析不含年参数</span></div>
        <el-input :value="preTimeList" :rows="5" type="textarea" readonly />
      </div>
      <div class="message">{{ cronValidatorMessage }}</div>
    </div>
  </div>
</template>

<script setup lang="ts">
  import { reactive, computed, ref, watch, nextTick } from 'vue'
  import CronParser from 'cron-parser'
  import { debounce } from 'lodash-es'
  import { dateFormat } from '/@/utils/dateUtils'
  import CronValidator from './validator'
  import { stringUtils } from '/@/utils/stringUtils'
  import { isNumber } from '/@/utils/isUtils'

  /**
   * 选中页签
   */
  const tabsActiveName = ref('second')

  //////////////////////////////////////////////////
  // 实现组件的v-model属性
  //////////////////////////////////////////////////

  // update: 需要双向绑定的属性名
  const emit = defineEmits(['update:modelValue'])

  //v-model 默认的值为 value 可以通过 : 自定义
  interface Props {
    modelValue: string
  }
  const props = withDefaults(defineProps<Props>(), {
    modelValue: ''
  })

  const cronModelValue = ref('')

  //监听父组件的值
  watch(
    () => props.modelValue,
    () => {
      cronModelValue.value = props.modelValue
      nextTick(() => {
        formatValue()

        handleCronValidator(props.modelValue)
      })
    },
    {
      immediate: true
    }
  )

  /**
   * 将值传递给父组件
   */
  function updateValue() {
    cronModelValue.value = cronValue.value
    // 通过emit将值传递给父组件
    emit('update:modelValue', cronModelValue.value)
  }

  //////////////////////////////////////////////////
  // 预览
  //////////////////////////////////////////////////

  /**
   * 执行时间
   */
  const startTime = ref(new Date())

  /**
   * 执行预览
   */
  const preTimeList = ref('')

  /**
   * 验证提示信息
   */
  const cronValidatorMessage = ref('')

  const tableData = computed(() => {
    let rows: any[] = [{ name: '秒', value: second.value }]

    rows = rows.concat([
      { name: '分', value: minute.value },
      { name: '时', value: hour.value },
      { name: '日', value: day.value },
      { name: '月', value: month.value },
      { name: '周', value: week.value }
    ])

    rows = rows.concat(
      { name: '年', value: year.value },
      { name: '表达式', value: cronValue },
      { name: '表达式(不含年)', value: cronNotYearValue }
    )

    return rows
  })

  /**
   * 计算表达式
   */
  const cronValue = computed(() => {
    let result: Array<string> = []
    result.push(second.value ? second.value : '*')
    result.push(minute.value ? minute.value : '*')
    result.push(hour.value ? hour.value : '*')
    result.push(day.value ? day.value : '*')
    result.push(month.value ? month.value : '*')
    result.push(week.value ? week.value : '?')
    result.push(year.value ? year.value : '*')
    return result.join(' ')
  })

  /**
   * 计算表达式(不含年)
   */
  const cronNotYearValue = computed(() => {
    const v = cronValue.value
    const vs = v.split(' ')
    return vs.slice(0, vs.length - 1).join(' ')
  })

  /**
   * 防抖
   */
  const calTriggerList = debounce(
    function () {
      calTriggerListInner()
    },
    500,
    {
      maxWait: 1000
    }
  )

  /**
   * 执行预览
   */
  function calTriggerListInner() {
    // 去掉年份参数
    const e = cronNotYearValue.value
    const format = 'yyyy-MM-dd hh:mm:ss'
    const options = {
      currentDate: dateFormat(startTime.value, format)
    }
    const iter = CronParser.parseExpression(e, options)
    const result: Array<string> = []
    for (let i = 0; i < 5; i++) {
      const next = iter.next()
      result.push(dateFormat(next.toDate(), format))
    }
    preTimeList.value = result.length > 0 ? result.join('\n') : '无执行时间'

    handleCronValidator(cronValue.value)

    updateValue()
  }

  /**
   * 表达式验证
   * @param value
   */
  function handleCronValidator(value: string) {
    CronValidator({}, value, function (msg: string) {
      cronValidatorMessage.value = msg
    })
  }

  //////////////////////////////////////////////////
  // cron面板
  //////////////////////////////////////////////////
  /**
   * 组件大小
   */
  const cronSize: any = 'default'

  /*=========== 主要用于日和星期的互斥使用 =========== */
  const TYPE_NOT_SET = 'TYPE_NOT_SET'
  const TYPE_EVERY = 'TYPE_EVERY'
  const TYPE_RANGE = 'TYPE_RANGE'
  const TYPE_LOOP = 'TYPE_LOOP'
  const TYPE_WORK = 'TYPE_WORK'
  const TYPE_LAST = 'TYPE_LAST'
  const TYPE_SPECIFY = 'TYPE_SPECIFY'

  /**
   * 默认值
   */
  const DEFAULT_VALUE = '?'

  interface CronModel {
    id: string
    value: string
    type: string
    minValue: number
    maxValue: number
    disabled: boolean
    range: {
      start: number
      end: number
    }
    loop: {
      start: number
      interval: number
    }
    valueList: Array<string>
    valueWork?: number
    weekMap?: object
  }

  /**
   * 秒
   */
  const second: CronModel = reactive({
    id: 'second',
    value: '*',
    type: TYPE_EVERY,
    minValue: 0,
    maxValue: 59,
    disabled: false,
    range: {
      start: 0,
      end: 59
    },
    loop: {
      start: 0,
      interval: 1
    },
    valueList: []
  })

  /**
   * 分
   */
  const minute: CronModel = reactive({
    id: 'minute',
    value: '*',
    type: TYPE_EVERY,
    minValue: 0,
    maxValue: 59,
    disabled: false,
    range: {
      start: 0,
      end: 59
    },
    loop: {
      start: 0,
      interval: 1
    },
    valueList: []
  })

  /**
   * 时
   */
  const hour: CronModel = reactive({
    id: 'hour',
    value: '*',
    type: TYPE_EVERY,
    minValue: 0,
    maxValue: 23,
    disabled: false,
    range: {
      start: 0,
      end: 23
    },
    loop: {
      start: 0,
      interval: 1
    },
    valueList: []
  })

  /**
   * 日
   */
  const day: CronModel = reactive({
    id: 'day',
    value: '*',
    type: TYPE_EVERY,
    minValue: 1,
    maxValue: 31,
    disabled: false,
    range: {
      start: 1,
      end: 31
    },
    loop: {
      start: 1,
      interval: 1
    },
    valueList: [],
    valueWork: 1
  })

  /**
   * 日和周只能设置其中之一
   */
  const dayDisable = computed(() => {
    return day.disabled || week.type !== TYPE_NOT_SET
  })

  /**
   * 月
   */
  const month: CronModel = reactive({
    id: 'month',
    value: '*',
    type: TYPE_EVERY,
    minValue: 1,
    maxValue: 12,
    disabled: false,
    range: {
      start: 1,
      end: 12
    },
    loop: {
      start: 1,
      interval: 1
    },
    valueList: []
  })

  /**
   * 周
   */
  const week: CronModel = reactive({
    id: 'week',
    value: '?',
    type: TYPE_NOT_SET,
    minValue: 0,
    maxValue: 6,
    disabled: false,
    range: {
      start: 0,
      end: 6
    },
    loop: {
      start: 2,
      interval: 1
    },
    valueList: [],
    weekMap: {
      周日: 1,
      周一: 2,
      周二: 3,
      周三: 4,
      周四: 5,
      周五: 6,
      周六: 7
    }
  })

  /**
   * 日和周只能设置其中之一
   */
  const weekDisable = computed(() => {
    return week.disabled || day.type !== TYPE_NOT_SET
  })

  /**
   * 年
   */
  const nowYear = new Date().getFullYear()
  const year: CronModel = reactive({
    id: 'year',
    value: '*',
    type: TYPE_EVERY,
    minValue: 0,
    maxValue: 0,
    disabled: false,
    range: {
      start: nowYear,
      end: nowYear + 100
    },
    loop: {
      start: nowYear,
      interval: 1
    },
    valueList: []
  })

  //////////////////////////////////////////////////
  // 构建表达式
  //////////////////////////////////////////////////

  watch(
    [second, minute, hour, day, month, week, year],
    (newValue) => {
      newValue.forEach((item) => {
        buildCron(item)
      })

      calTriggerList()
    },
    {
      deep: true,
      immediate: true
    }
  )

  /**
   * 构建表达式
   */
  function buildCron(params: CronModel) {
    let result: Array<string> = []
    switch (params.type) {
      case TYPE_NOT_SET:
        result.push('?')
        break
      case TYPE_EVERY:
        result.push('*')
        break
      case TYPE_RANGE:
        result.push(`${params.range.start}-${params.range.end}`)
        break
      case TYPE_LOOP:
        result.push(`${params.loop.start}/${params.loop.interval}`)
        break
      case TYPE_WORK:
        result.push(`${params.valueWork}W`)
        break
      case TYPE_LAST:
        result.push('L')
        break
      case TYPE_SPECIFY:
        let valueList = params.valueList
        if (params.valueList[0] === '*') {
          valueList = params.valueList.slice(1)
        }
        result.push(valueList.join(','))
        break
      default:
        result.push(DEFAULT_VALUE)
        break
    }
    params.value = result.length > 0 ? result.join('') : DEFAULT_VALUE
  }

  //////////////////////////////////////////////////
  // 解析表达式
  //////////////////////////////////////////////////

  /**
   * 格式化表达式
   */
  function formatValue() {
    if (stringUtils.isEmpty(cronModelValue.value)) {
      return
    }
    const values = cronModelValue.value?.split(' ').filter((item) => !!item)
    if (!values || values.length <= 0) {
      return
    }

    let i = 0

    parse(second, values[i++])
    if (values.length > i) parse(minute, values[i++])
    if (values.length > i) parse(hour, values[i++])
    if (values.length > i) parse(day, values[i++])
    if (values.length > i) parse(month, values[i++])
    if (values.length > i) parse(week, values[i++])
    if (values.length > i) parse(year, values[i++])
  }

  /**
   * 解析表达式
   */
  function parse(params: CronModel, value: string) {
    if (params.value === value) {
      // console.info('same ' + value)
      return
    }

    try {
      if (!value || value === DEFAULT_VALUE) {
        params.type = TYPE_NOT_SET
      } else if (value.indexOf('?') >= 0) {
        params.type = TYPE_NOT_SET
      } else if (value.indexOf('-') >= 0) {
        params.type = TYPE_RANGE
        const values = value.split('-')
        if (values.length >= 2) {
          params.range.start = parseInt(values[0])
          params.range.end = parseInt(values[1])
        }
      } else if (value.indexOf('/') >= 0) {
        params.type = TYPE_LOOP
        const values = value.split('/')
        if (values.length >= 2) {
          params.loop.start = value[0] === '*' ? 0 : parseInt(values[0])
          params.loop.interval = parseInt(values[1])
        }
      } else if (value.indexOf('W') >= 0) {
        params.type = TYPE_WORK
        const values = value.split('W')
        if (!values[0] && !isNumber(values[0])) {
          params.valueWork = parseInt(values[0])
        }
      } else if (value.indexOf('L') >= 0) {
        params.type = TYPE_LAST
      } else if (value.indexOf(',') >= 0 || !isNumber(value)) {
        params.type = TYPE_SPECIFY
        params.valueList = value.split(',').map((item) => item)
      } else {
        params.type = TYPE_EVERY
      }
    } catch (e) {
      // console.info(e)
      params.type = TYPE_EVERY
    }
  }
</script>

<style scoped lang="scss">
  .tw-cron-wrapper {
    display: flex;
    width: 900px;
    padding: 10px;
    border: 1px solid #2d8cf0;
    border-radius: 3px;

    .el-divider {
      height: 100%;
      background-color: #2d8cf0;
    }

    .left-wrapper {
      flex-basis: 60%;
      width: 60%;

      .config-list {
        font-size: 12px;

        .item {
          padding: 10px 0px;

          .info {
            color: #909399;
          }
          .list {
            margin-left: 20px;

            .el-checkbox {
              width: 50px;
            }
          }
        }
      }
    }

    .right-wrapper {
      flex-basis: 40%;
      width: 40%;
      font-size: 14px;

      .lable {
        margin-bottom: 5px;

        span {
          font-size: 12px;
          color: #909399;
        }
      }

      .table {
        margin-bottom: 10px;
      }
      .exe-time {
        margin-bottom: 10px;
      }
      .message {
        margin-top: 10px;
        font-size: 12px;
        color: #f56c6c;
      }
    }
  }
</style>
